using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;

namespace HB.CacheDb
{
    /// <summary>
    /// 查询实体
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class Query<T> where T : class, new()
    {


        CollectionItem collection { get; set; }
        ICacheDbCallBack DBCallBack { get; set; }
        int timeout = 5000;
        T DeepCopyFun(T old)
        {
            if (old == null) { return old; }
            if (!collection.UseDeepCopy) { return old; }
            if (collection.deepCopyFunc != null) { return collection.deepCopyFunc.Invoke(old); }
            else
            {
                return old.DeepCopyByReflection();
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="collection"></param>
        /// <param name="callBack"></param>
        /// <param name="timeout"></param>
        public Query(CollectionItem collection, ICacheDbCallBack callBack, int timeout)
        {
            this.collection = collection;
            this.DBCallBack = callBack;
            this.timeout = timeout;
        }
        /// <summary>
        /// 是否包含元素
        /// </summary>
        /// <param name="o"></param>
        /// <returns></returns>
        public bool ContainKey(object o)
        {
            if (o == null) { return false; }
            return collection.Dic.ContainsKey(o);
        }
        /// <summary>
        /// 通过可以取得实体
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public T GetValue(object key)
        {
            if (key == null) { return null; }
            if (collection.Dic.ContainsKey(key))
            {
                return DeepCopyFun(collection.Dic[key] as T);
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// 直接使用原始的实例
        /// </summary>
        /// <param name="key"></param>
        /// <param name="valueCallback"></param>
        public void UseReferenceValue(object key, Action<T> valueCallback)
        {
            if (key == null) { return; }
            if (collection.Dic.ContainsKey(key))
            {
                valueCallback(collection.Dic[key] as T);
            }
        }
        IEnumerable<T> Values => collection.Dic.Values.Cast<T>();
        /// <summary>
        /// 添加单个对象，同步到数据库后更新内存,请使用AddOrUpdate代替
        /// </summary>
        /// <param name="value"></param>
        [Obsolete]
        public bool Add(T value)
        {
            return QueueDo(() =>
              {

                  var b = DBCallBack?.Add(value);
                  if (b != false)
                  {
                      collection.Dic[collection.getKey(value)] = DeepCopyFun(value);
                  }
                  return b == true;
              }, false);

        }

        /// <summary>
        /// 批量增加对象，同步到数据库后更新内存
        /// </summary>
        /// <param name="datas"></param>
        public bool AddAll(List<T> datas)
        {
            return QueueDo(() =>
            {

                var b = DBCallBack?.AddAll(datas);
                if (b != false)
                {
                    foreach (var data in datas.Select(zz => DeepCopyFun(zz)))
                    {
                        collection.Dic[collection.getKey(data)] = data;
                    }
                }
                return b == true;
            }, false);
        }
        /// <summary>
        /// 添加或更新，同步到数据库后更新内存
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool AddOrUpdate(T value)
        {
            var key = collection.getKey(value);
            bool exists = false;
            return QueueDo(() =>
            {
                exists = collection.Dic.ContainsKey(key);
                bool b = false;
                if (exists)
                {
                    b = DBCallBack?.Update(value) != false;
                }
                else
                {

                    b = DBCallBack?.Add(value) != false;


                }
                if (b)
                {
                    collection.Dic[key] = DeepCopyFun(value);
                }
                return b;

            }, false);
        }
        /// <summary>
        /// 更新数据，同步到数据库后更新内存
        /// </summary>
        /// <param name="obj"></param>
        public bool Update(T obj)
        {
            return QueueDo(() =>
            {
                bool b = true;
                var key = collection.getKey(obj);
                if (collection.Dic.ContainsKey(key))
                {
                    b = DBCallBack?.Update(obj) != false;
                    if (b)
                    {
                        collection.Dic[key] = DeepCopyFun(obj);
                    }
                }
                return b;
            }, false);


        }
        /// <summary>
        /// 更新所有，同步到数据库后更新内存
        /// </summary>
        /// <param name="datas"></param>
        public bool UpdateAll(List<T> datas)
        {
            return QueueDo(() =>
            {
                bool b = true;
                foreach (var data in datas)
                {
                    if (!collection.Dic.ContainsKey(collection.getKey(data)))
                    {
                        b = false;
                    }
                }
                if (b)
                {
                    b = DBCallBack?.UpdateAll(datas) != false;
                }
                if (b)
                {
                    foreach (var data in datas.Select(zz => DeepCopyFun(zz)))
                    {
                        collection.Dic[collection.getKey(data)] = data;
                    }
                }
                return b;
            }, false);
        }
        /// <summary>
        /// 删除符合条件的对象，同步到数据库后更新内存
        /// </summary>
        /// <param name="ex"></param>
        public bool Delete(Expression<Func<T, bool>> ex)
        {
            return QueueDo(() =>
            {
                bool b = true;
                var datas = Values.Where(ex.Compile()).ToList();
                if (datas.Count > 0)
                {
                    b = DBCallBack?.Delete(ex) != false;
                    if (b)
                    {
                        foreach (var data in datas)
                        {
                            collection.Dic.TryRemove(collection.getKey(data), out dynamic obj);
                        }
                    }
                }
                return b;
            }, false);


        }

        /// <summary>
        /// 是否包含符合条件的元素，使用Any查询
        /// </summary>
        /// <param name="ex"></param>
        /// <returns></returns>
        public bool Exists(Expression<Func<T, bool>> ex)
        {
            return QueueDo(() =>
            {
                return Values.Where(ex.Compile()).Any();
            }, false);

        }
        /// <summary>
        /// 获取符合条件的第一个元素
        /// </summary>
        /// <param name="ex"></param>
        /// <returns></returns>
        public T FirstOrDefault(Expression<Func<T, bool>> ex)
        {
            return QueueDo(() =>
            {
                return DeepCopyFun(Values.Where(ex.Compile()).FirstOrDefault());
            }, default(T));
        }

        T2 QueueDo<T2>(Func<T2> a, T2 FailValue)
        {
            T2 t = default(T2);
            if (Monitor.TryEnter(collection, timeout))
            {
                try
                {
                    t = a.Invoke();
                }
                catch
                {
                    t = FailValue;
                }
                finally
                {
                    Monitor.Exit(collection);
                }
                return t;
            }
            else
            {
                return FailValue;
            }
        }
        /// <summary>
        /// 返回符合条件的list
        /// </summary>
        /// <param name="ex"></param>
        /// <returns></returns>
        public List<T> Where(Expression<Func<T, bool>> ex)
        {
            return QueueDo(() =>
            {
                return Values.Where(ex.Compile()).Select(zz => DeepCopyFun(zz)).ToList();
            }, new List<T>());

        }
        /// <summary>
        /// 获取所有数据
        /// </summary>
        /// <returns></returns>
        public List<T> ToList()
        {
            return QueueDo(() =>
            {
                return Values.Select(zz => DeepCopyFun(zz)).ToList();
            }, new List<T>());

        }
        /// <summary>
        /// 获取元素总数
        /// </summary>
        /// <returns></returns>
        public int Count()
        {
            return QueueDo(() =>
            {
                return Values.Count();
            }, 0);
        }
    }
}
